package com.atwisdom.star.core.bsl.customized.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.atwisdom.star.common.vo.JsonResult;
import com.atwisdom.star.common.vo.ModelType;
import com.atwisdom.star.common.vo.ResultInfo;
import com.atwisdom.star.common.vo.StatusCode;
import com.atwisdom.star.core.bsl.customized.CustomizeBusinessBslService;
import com.atwisdom.star.core.bsl.planner.Impl.MaterialBslServiceImpl;
import com.atwisdom.star.core.bsl.planner.Impl.ProductBomBslServiceImpl;
import com.atwisdom.star.core.bsl.planner.Impl.WorkProcessPathBslServiceImpl;
import com.atwisdom.star.core.bsl.planner.entity.Material;
import com.atwisdom.star.core.bsl.planner.entity.ProductBomLevel;
import com.atwisdom.star.core.bsl.planner.entity.ProductBomMaster;
import com.atwisdom.star.core.dao.pojo.modelClass.hier.HierInstance;
import com.atwisdom.star.core.dao.pojo.modelClass.hier.HierModel;
import com.atwisdom.star.core.dsl.functionClass.Impl.BatchNumberDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.hier.HierInstanceDslService;
import com.atwisdom.star.core.dsl.modelClass.logic.Impl.LogicInstanceDslServiceImpl;
import com.atwisdom.star.exception.pojo.BusinessException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;


@Slf4j
@AllArgsConstructor
@Service
public class CustomizeBusinessBslServiceImpl implements CustomizeBusinessBslService {

    private LogicInstanceDslServiceImpl logicInstanceDslService;
    private HierInstanceDslService hierInstanceDslService;
    private ProductBomBslServiceImpl productBomBslService;
    private MaterialBslServiceImpl materialBslService;
    private WorkProcessPathBslServiceImpl workProcessPathBslService;
    private BatchNumberDslServiceImpl batchNumberDslService;

    @Autowired
    public void setLogicInstanceDslService(LogicInstanceDslServiceImpl logicInstanceDslService) {
        this.logicInstanceDslService = logicInstanceDslService;
    }

    @Autowired
    public void setHierInstanceDslService(HierInstanceDslService hierInstanceDslService) {
        this.hierInstanceDslService = hierInstanceDslService;
    }

    @Autowired
    public void setProductBomBslService(ProductBomBslServiceImpl productBomBslService) {
        this.productBomBslService = productBomBslService;
    }

    @Autowired
    public void setMaterialBslService(MaterialBslServiceImpl materialBslService) {
        this.materialBslService = materialBslService;
    }
    @Autowired
    public void setWorkProcessPathBslService(WorkProcessPathBslServiceImpl workProcessPathBslService) {
        this.workProcessPathBslService = workProcessPathBslService;
    }
    @Autowired
    public void setBatchNumberDslService(BatchNumberDslServiceImpl batchNumberDslService) {
        this.batchNumberDslService = batchNumberDslService;
    }

    /**
     * 实例数据拆分
     *     {
     *      model: "logic",
     *      isHier: true, // 是否是复制 hier的数据
     *      id: 123, // 如果 isHier=true 就是子表id，否则是主表id
     *      splitKey: "quantity" // 拆分的字段
     *      splitList: [12, 16]  // 用户输入的拆分数量,必须为浮点数据
     *     }
     * @param splitData 拆分接口参数
     * @return 返回拆分实例数据
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResultInfo<?> splitInstanceData(JSONObject splitData) {
        String model = splitData.getString("model");
        Boolean isHier = splitData.getBoolean("isHier");
        Long id = splitData.getLong("id");
        String splitKey = splitData.getString("splitKey");
        JSONArray splitList = splitData.getJSONArray("splitList");
        List<Double> quantityList = JSONUtil.parseArray(splitList).toList(Double.class);
        List<JSONObject> resultJsonList;
        if(isHier){
            resultJsonList = splitHierInstanceData(id, quantityList, splitKey);
        }else{
            resultJsonList = splitLogicInstanceData(id, quantityList, splitKey);
        }
        return JsonResult.success(resultJsonList);
    }


    /**
     * 看板产线相关数据获取（看板打印使用）
     * @param params  参数结构：
     *  params: {
     *     bcodes: ['b1', 'b2']
     * }
     * @return
     */
    @Override
    public ResultInfo<?> getKanbanProductLine(JSONObject params) {
        JSONArray bCodes = params.getJSONArray("bcodes");
        List<String> bcodeList = JSONUtil.parseArray(bCodes).toList(String.class);
        this.productBomBslService.initBOM();
        JSONObject resultJson = new JSONObject();
        for (String bCode:bcodeList) {
            this.productBomBslService.buildProductBomLevel(bCode);
            List<ProductBomLevel> productBomLevels = this.productBomBslService.getProductBomLevels();
            List<JSONObject> jsonList = new ArrayList<>();
            for (ProductBomLevel productBomLevel:productBomLevels) {
                JSONObject jsonObject = new JSONObject();
                String materialBCode = productBomLevel.getMaterialBCode();
                this.materialBslService.initMaterialByCondition(" bcode = '"+materialBCode+"'");
                List<Material> materials = this.materialBslService.getMaterials();
                Material material = materials.stream().filter(m -> m.getBcode().equalsIgnoreCase(materialBCode)).findFirst().orElse(null);
                if(material == null){
                    continue;
                }

                String materialAttr =material.getAttr();
                if( materialAttr == null || !materialAttr.equals("produce")){
                    continue;
                }

                Integer acceptQuantity = material.getAcceptQuantity();
                if(acceptQuantity == null){
                    acceptQuantity = 1;
                }
                String defaultContainer = material.getDefaultContainer();
                jsonObject.put("bcode", material.getBcode());
                jsonObject.put("pcode", material.getPcode());
                jsonObject.put("acceptQuantity",acceptQuantity);
                jsonObject.put("defaultContainer",defaultContainer);
                setProductLine(materialBCode, jsonObject, jsonList);
            }
            resultJson.put(bCode, jsonList);
        }
        return JsonResult.success(resultJson);
    }


    /**
     * 生成看板打印模板生产线设置
     * @param materialBCode 背番
     * @param jsonObject 参数
     * @param jsonList 参数
     */
    private void setProductLine(String materialBCode, JSONObject jsonObject, List<JSONObject> jsonList) {
        ProductBomMaster productBomMaster = this.productBomBslService.getProductBomList().stream().filter(pb -> materialBCode.equalsIgnoreCase(pb.getMaterialBCode())).findFirst().orElse(null);
        if(productBomMaster!=null){
            String bomType = productBomMaster.getBomType();
            String bomCode = productBomMaster.getBomCode();
            if(bomType.equals("combined")){
                this.workProcessPathBslService.initWorkProcessPathByCondition(" combinedBOMCode = '"+bomCode+"'");
            }else{
                this.workProcessPathBslService.initWorkProcessPathByCondition(" splitBOMCode = '"+bomCode+"'");
            }
        }
        JSONObject wppJson = workProcessPathBslService.getWppEquipList(materialBCode);
        if(wppJson!=null){
            String lineBodyName = wppJson.getString("lineBodyName");
            jsonObject.put("productLine",lineBodyName);
        }else{
            jsonObject.put("productLine",null);
        }
        jsonList.add(jsonObject);
    }

    private List<JSONObject>  splitLogicInstanceData(Long id, List<Double> quantityList,String splitKey){
        JSONObject jsonObject = logicInstanceDslService.queryJsonById(id);
        List<JSONObject> opDataList = new ArrayList<>();
        for (int i = 0; i < quantityList.size(); i++) {
            Double quantity = quantityList.get(i);
            JSONObject jsonIns = new JSONObject();
            BeanUtil.copyProperties(jsonObject, jsonIns);
            JSONObject values = jsonIns.getJSONObject("values");
            values.put(splitKey,quantity);
            if (i != 0) {
                jsonIns.put("id", null);
            }
            opDataList.add(jsonIns);
        }
        return logicInstanceDslService.batchAddOrUpdate(opDataList);
    }

    private List<JSONObject> splitHierInstanceData(Long id, List<Double> quantityList, String splitKey) {
        HierInstance hierInstance = this.hierInstanceDslService.queryHierInsById(id);
        JSONObject jsonObject = this.hierInstanceDslService.convertValuesByProperty(hierInstance);
        HierModel hierModel = this.hierInstanceDslService.fetchFirstHierModelWithProperty(hierInstance);
        List<JSONObject> opDataList = new ArrayList<>();
        for (int i = 0; i < quantityList.size(); i++) {
            Double quantity = quantityList.get(i);
            JSONObject jsonIns = JSON.parseObject(jsonObject.toJSONString(), JSONObject.class);
            JSONObject values = jsonIns.getJSONObject("values");
            values.put(splitKey, quantity);
            if (i != 0) {
                jsonIns.put("id", null);
                JSONObject addJsonObject = this.hierInstanceDslService.convertValuesByProperty(this.hierInstanceDslService.addChild(jsonIns));
                opDataList.add(addJsonObject);
            } else {
                HierInstance newHierInstance = this.hierInstanceDslService.buildNewInstance(hierModel, jsonIns);
                JSONObject updateJsonObject = this.hierInstanceDslService.convertValuesByProperty(this.hierInstanceDslService.updateById(newHierInstance));
                opDataList.add(updateJsonObject);
            }
        }
        return opDataList;
    }

    /**
     * 拆分拣料单数据
     * @param params
     * @return
     */
    @Override
    public ResultInfo<?> splitPickMaterialData(JSONObject params) {
        Long id = params.getLong("id");
        // 扫描父类id
        String scanParentId = params.getString("scanParentId");
        //领料父类id
        String pickParentId = params.getString("pickParentId");
        JSONObject jsonObject = logicInstanceDslService.queryJsonById(id);
        if (jsonObject == null) {
            return JsonResult.success(JsonResult.success().getCode(),"未查到派料单，拆单无效 ！");
        }

        List<HierInstance> hierInstanceList = this.hierInstanceDslService.queryByContainerId(ModelType.Logic.getCode(), id);
        if (hierInstanceList.size() == 0) {
            return JsonResult.success(JsonResult.success().getCode(),"物料记录不存，拆单无效！");
        }

        List<HierInstance> pickHierInstanceList = new ArrayList<>();
        for (HierInstance hIns : hierInstanceList) {
            String parentId = hIns.getParentId();
            if (parentId.equals(scanParentId)) {
                continue;
            }
            hIns.setId(null);
            if (parentId.equals(pickParentId)) {
                JSONObject values = hIns.getValues();
                Integer quantity = values.getInteger("quantity");
                if(quantity == null){
                    quantity = 0;
                }
                Integer pickQuantity = values.getInteger("pickQuantity");
                if(pickQuantity == null){
                    pickQuantity = 0;
                }

                if(quantity > pickQuantity){
                    values.put("quantity",quantity-pickQuantity);
                    values.put("pickQuantity",0);
                    values.put("pickSubQuantity",0);
                    hIns.setValues(values);
                    pickHierInstanceList.add(hIns);
                }
            }
        }
        String number = String.format("distributeOrder");
        this.genSplitAfterData(pickHierInstanceList, jsonObject,"number",number);
        return JsonResult.success(JsonResult.success());
    }

    /**
     * 拆分采购订单入库单
     * @param params
     * @return
     */
    @Override
    public ResultInfo<?> splitPurchaseOrderInData(JSONObject params) {
        Long id = params.getLong("id");
        //扫描明细id
        String scanParentId = params.getString("scanParentId");
        //货码明细id
        String detailParentId = params.getString("detailParentId");
        JSONObject jsonObject = logicInstanceDslService.queryJsonById(id);

        if (jsonObject == null) {
            return JsonResult.success(JsonResult.success().getCode(),"未查到入库单，拆单无效 ！");
        }

        List<HierInstance> hierInstanceList = this.hierInstanceDslService.queryByContainerId(ModelType.Logic.getCode(), id);
        if (hierInstanceList.size() == 0) {
            return JsonResult.success(JsonResult.success().getCode(),"货码记录不存，拆单无效！");
        }
        List<HierInstance> detailHierInstanceList = new ArrayList<>();
        for (HierInstance hIns : hierInstanceList) {
            String parentId = hIns.getParentId();
            JSONObject values = hIns.getValues();
            Integer status = values.getInteger("status");
            if(status == null){
                status = 0;
            }
            hIns.setId(null);
            //未扫码拆分生成新入库单货码明细，并将扫码明细和货码明细实例根数据复制到下个单据（parentId 是null或root）
            if ((parentId.equals(detailParentId) && status < 1)){
                detailHierInstanceList.add(hIns);
            }else if(parentId.equals(scanParentId)){
                Double quantity = values.getDouble("quantity");
                if(quantity == null){
                    quantity = 0.0;
                }
                Double subQuantity = values.getDouble("subQuantity");
                if(subQuantity == null){
                    subQuantity = 1.0;
                }
                Double arrivalQuantity = values.getDouble("arrivalQuantity");
                if(arrivalQuantity == null){
                    arrivalQuantity = 0.0;
                }
                Double arrivalSubQuantity = values.getDouble("arrivalSubQuantity");
                if(arrivalSubQuantity == null){
                    arrivalSubQuantity = 0.0;
                }
                if(quantity > arrivalQuantity){
                    values.put("quantity",quantity-arrivalQuantity);
                    values.put("subQuantity",subQuantity-arrivalSubQuantity);
                    values.put("arrivalQuantity",0);
                    values.put("arrivalSubQuantity",0);
                    detailHierInstanceList.add(hIns);
                }
            }
        }

        int year = LocalDate.now().getYear();
        String number = String.format("receiptOrder-%s", year);
        System.out.println("生成入库单前缀名称："+number);
        JSONObject values = jsonObject.getJSONObject("values");
        values.put("status", 0);
        this.genSplitAfterData(detailHierInstanceList, jsonObject,"code",number);
        return JsonResult.success(JsonResult.success());
    }

    /**
     * 工单撤销
     * @param params  参数结构：
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultInfo<?> workOrderRevoke(JSONObject params) {
        Long id = params.getLong("id");
        JSONObject workOrderJson = logicInstanceDslService.queryJsonById(id);
        if(workOrderJson == null){
            return JsonResult.error(StatusCode.ERROR_WORK_ORDER_NOT_FOUND_REVOKE);
        }

        String materialCondition = " className = 'materialRecord' and workOrder_id= "+id;
        List<JSONObject> materialRecordList = logicInstanceDslService.query(materialCondition, "materialRecord");
        if(CollectionUtil.isNotEmpty(materialRecordList)){
//            return JsonResult.error(StatusCode.ERROR_WORK_ORDER_EXIST_SUB_DATA_REVOKE);
            throw new BusinessException(StatusCode.ERROR_WORK_ORDER_EXIST_SUB_DATA_REVOKE.getCode(), StatusCode.ERROR_WORK_ORDER_EXIST_SUB_DATA_REVOKE.getMessage());
        }

        String reportCondition = " className = 'workReport' and workOrder_id= "+id;
        List<JSONObject> workReportList = logicInstanceDslService.query(reportCondition, "workReport");
        if(CollectionUtil.isNotEmpty(workReportList)){
//            return JsonResult.error(StatusCode.ERROR_WORK_ORDER_EXIST_SUB_DATA_REVOKE);
            throw new BusinessException(StatusCode.ERROR_WORK_ORDER_EXIST_SUB_DATA_REVOKE.getCode(), StatusCode.ERROR_WORK_ORDER_EXIST_SUB_DATA_REVOKE.getMessage());
        }

        //更新工单状态
        JSONObject values = new JSONObject();
        values.put("status", "revoke");
        JSONObject orderJson = new JSONObject();
        orderJson.put("id", id);
        orderJson.put("className", "workOrder");
        orderJson.put("type", "logic");
        orderJson.put("values", values);
        logicInstanceDslService.updateById(orderJson);

        //更新生产计划订单创建状态
        JSONObject workOrderValues = workOrderJson.getJSONObject("values");
        Long planId = workOrderValues.getLong("planId");
        if(planId != null){
            JSONObject planValues = new JSONObject();
            planValues.put("isCreate", "false");
            JSONObject planOrderJson = new JSONObject();
            planOrderJson.put("id", planId);
            planOrderJson.put("className", "ProductionPlanOrder");
            planOrderJson.put("type", "logic");
            planOrderJson.put("values", planValues);
            logicInstanceDslService.updateById(planOrderJson);
        }
        return JsonResult.success(StatusCode.SUCCESS.getCode(),"工单撤销成功！");
    }

    @Override
    public ResultInfo<?> productionPlanOrderUnlock(JSONObject params) {
        Long id = params.getLong("id");
        JSONObject planOrderJson = logicInstanceDslService.queryJsonById(id);
        if(planOrderJson == null){
            throw new BusinessException(StatusCode.ERROR_PRODUCTION_PLAN_ORDER_NOT_FOUND.getCode(), StatusCode.ERROR_PRODUCTION_PLAN_ORDER_NOT_FOUND.getMessage());
        }

        JSONObject jsonObject = planOrderJson.getJSONObject("values");
        Boolean isCreate = jsonObject.getBoolean("isCreate");
        if(isCreate != null && isCreate){
            throw new BusinessException(StatusCode.ERROR_WORK_ORDER_IS_CREATED.getCode(), StatusCode.ERROR_WORK_ORDER_IS_CREATED.getMessage());
        }

        Boolean isLock = jsonObject.getBoolean("isLock");
        if(isLock == null || !isLock){
            throw new BusinessException(StatusCode.ERROR_PRODUCTION_PLAN_ORDER_NOT_LOCK.getCode(), StatusCode.ERROR_PRODUCTION_PLAN_ORDER_NOT_LOCK.getMessage());
        }

        JSONObject planValues = new JSONObject();
        planValues.put("isLock", "false");
        JSONObject planJson = new JSONObject();
        planJson.put("id", id);
        planJson.put("className", "ProductionPlanOrder");
        planJson.put("type", "logic");
        planJson.put("values", planValues);
        logicInstanceDslService.updateById(planJson);
        return JsonResult.success(StatusCode.SUCCESS.getCode(),"生产计划订单解锁成功！");
    }

    /**
     * 生成拆分后单据
     * @param hierInstanceList
     * @param masterJson
     */
    private void genSplitAfterData(List<HierInstance> hierInstanceList, JSONObject masterJson, String numberKey,String numberValue) {
        if(hierInstanceList.size() == 0){
            return;
        }

        JSONObject values = masterJson.getJSONObject("values");
        String newNumber = batchNumberDslService.getNextVal(numberValue);
        values.put(numberKey, newNumber);
        values.put("isApproved", false);
        masterJson.put("id", null);

        JSONObject newLogicJson = logicInstanceDslService.add(masterJson);
        if (newLogicJson == null) {
            return;
        }

        Long newLogicId = newLogicJson.getLong("id");
        for (HierInstance hierInstance : hierInstanceList) {
            HierModel hierModel = this.hierInstanceDslService.fetchFirstHierModelWithProperty(hierInstance);
            hierInstance.setContainerId(newLogicId);
            hierInstance.setId(null);
            JSONObject hierInstanceJson = JSONObject.parseObject(JSON.toJSONString(hierInstance), JSONObject.class);
            HierInstance newHierInstance = this.hierInstanceDslService.buildNewInstance(hierModel, hierInstanceJson);
            this.hierInstanceDslService.add(newHierInstance);
        }
    }

    /**
     * 将质检不良、报废回写到报工明细
     * @param params  参数结构：
     * @return
     */
    @Override
    public ResultInfo<?> writeBackWorkReport(JSONObject params) {
        if(params == null){
            return JsonResult.error(StatusCode.ERROR_PARAM_NULL);
        }

        Long qualityId = params.getLong("qualityId");
        JSONObject workQuality = logicInstanceDslService.queryJsonById(qualityId);
        JSONObject values = workQuality.getJSONObject("values");
        //质检报工看板明细数据
        JSONArray dataList = values.getJSONArray("dataList");
        //质检报工不良数据
        JSONArray dataPoorList = values.getJSONArray("dataPoorList");
        //质检报工报废数据
        Integer scrapNumber = values.getInteger("scrapNumber");
        if(scrapNumber == null){
            scrapNumber = 0;
        }
        //质检报工不良数量
        Integer poorNumber = values.getInteger("poorNumber");
        if(poorNumber == null){
            poorNumber = 0;
        }
        //质检报工类型
        String qualityType = values.getString("qualityType");
        //判断质检报工类型是否是待检区质检
        if(qualityType.equalsIgnoreCase("productionQuality")){
            //报工明细id
            Long reportDetailId = values.getLong("source_id");
            JSONObject jsonObject = this.hierInstanceDslService.queryById(reportDetailId);
            JSONObject hierValues = jsonObject.getJSONObject("values");
            if(hierValues != null){
                //报工数量
                Integer workReportNumber = hierValues.getInteger("workReportNumber");
                if(workReportNumber==null){
                    workReportNumber = 0;
                }

                workReportNumber = workReportNumber + scrapNumber + poorNumber;


                //报工明细不良数量

                Integer reportDetailPoorNumber = hierValues.getInteger("poorNumber");
                //报工明细报废数量
                Integer reportDetailScrapNumber = hierValues.getInteger("scrapNumber");
                //报工明细不良数据
                JSONArray reportDetailPoorList = hierValues.getJSONArray("poorList");
                //报工明细报废数据

//                hierInstanceDslService.updateById(jsonObject);
            }


        }else{
            //工单Id
            Long workOrderId = values.getLong("source_id");
        }

        return null;
    }

    /**
     *更新报工单待检区不良、报废数据
     * @param params
     */
   private void updateWaitWorkQuality(JSONObject params){

    }

    /**
     * 更新报工单初中终质检不良、报废数据
     * @param params
     */
    private void updateFirstMidEndWorkQuality(JSONObject params){

    }
}
